package com.nuanshui.framework.res.qiniu.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.BasicDBObject;
import com.nuanshui.framework.cache.CacheConstants;
import com.nuanshui.framework.lang.SysStringUtils;
import com.nuanshui.framework.res.ResourceFacade;
import com.nuanshui.framework.res.UploadRequest;
import com.nuanshui.framework.res.qiniu.*;
import com.nuanshui.framework.res.qiniu.module.CallBackTimeModule;
import com.nuanshui.framework.res.qiniu.module.QiniuCallBack;
import com.nuanshui.framework.res.qiniu.module.QiniuPersistentModule;
import com.nuanshui.framework.res.qiniu.module.TransFormModule;
import com.nuanshui.framework.springContext.SpringContextUtil;
import com.nuanshui.framework.utils.HttpUtil;
import com.nuanshui.framework.utils.LogUtil;
import com.nuanshui.framework.utils.redis.JedisUtil;
import com.nuanshui.heatedloan.enums.FileBelong;
import com.nuanshui.heatedloan.model.Image;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.processing.OperationManager;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Recorder;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.qiniu.util.UrlSafeBase64;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

@Service("qiniu")
public class QiniuNonProdImpl implements Qiniu {

    @Value("${qiniu.scope}")
    String qiniuScope;

    @Value("${qiniu.pipeline}")
    String qiniuPipeline;

    @Value("${qiniu.video.callbackurl}")
    String convertVideoCallBackUrl;

    private Logger logger = LoggerFactory.getLogger(getClass());

    //@Autowired
    //private MongoManager mongoManager;

    @Autowired
    private JedisUtil jedisUtil;



    @Autowired
    QiniuBeanManager qiniuBeanManager;

    @Override
    public String genBucketName(FileBelong belong) {

        QiniuBean bean = qiniuBeanManager.findQiniuBeanByBelong(belong);

        if (bean != null) {
            return bean.bucketName;
        }
        return null;
    }

    @Override
    public String genBucketSiteHost(FileBelong belong) {
        QiniuBean bean = qiniuBeanManager.findQiniuBeanByBelong(belong);
        if (bean != null) {
            return bean.siteHost;
        }
        return null;
    }

    private Auth getAuth(String bucketName) {
        QiniuBean bean = qiniuBeanManager.findQiniuBeanByBucketName(bucketName);
        return Auth.create(bean.accessKey, bean.secretKey);
    }

    @Override
    public String genUpToken(String bucketName) {
        String returnBody = "{key: $(key), name:$(fname), size: $(fsize), w: $(imageInfo.width),"
                + "h: $(imageInfo.height), hash: $(etag), suffix:$(suffix), imageAve:$(imageAve) }";
        StringMap stringMap = new StringMap();
        stringMap.put("returnBody", returnBody);
        return getAuth(bucketName).uploadToken(bucketName, null, 36000, stringMap);
    }

    @Override
    public Map<String, Object> upToken() {
        String bucketName = genBucketName(FileBelong.PRODUCT);
        Auth auth = getAuth(bucketName);
        HashMap<String, Object> map = new HashMap<String, Object>();
        try {
            map.put("upToken", auth.uploadToken(qiniuScope));
        } catch (Exception e) {
            LogUtil.error(logger, "获取token失败！！！" + e);
        }
        return map;

    }


    @Override
    public void convertPostVideo(String sourceKey, String targetKey, String fops) {
        String bucketName = genBucketName(FileBelong.PRODUCT);
        Auth auth = getAuth(bucketName);

        //新建一个OperationManager对象
        OperationManager operator = new OperationManager(auth);

        //设置要转码的空间和key，并且这个key在你空间中存在
        String key = sourceKey;

        //设置pipeline参数
        StringMap params = new StringMap().putWhen("force", 1, true).putNotEmpty("pipeline", qiniuPipeline).put("notifyURL", convertVideoCallBackUrl);

        try {
            String persistId = operator.pfop(qiniuScope, key, fops, params);

            try {
                //記錄回調的開始時間
                CallBackTimeModule callBackTime = new CallBackTimeModule();
                callBackTime.setStartTime(new Date());
                callBackTime.setPersistentId(persistId);
                callBackTime.setEndTime(new Date());
                BasicDBObject basicDBObject = new BasicDBObject(JSON.parseObject(JSON.toJSONString(callBackTime)));

                //mongoManager.save("callBackTimeRecord", basicDBObject);
            } catch (Exception e) {
                LogUtil.error(logger, "回掉發起的時候，保存回調時間錯誤！。錯誤信息：" + e);
            }


            System.out.println("persistid=" + persistId + "sourceKey=" + sourceKey + "targetKey=" + targetKey);

            QiniuCallBack callBack = new QiniuCallBack();
            callBack.setId(persistId);
            callBack.setSourceKey(sourceKey);
            callBack.setTargetKey(targetKey);
            callBack.setIsCallBack(false);
            callBack.setIsSaved(false);

            jedisUtil.lpush(CacheConstants.QINIU_CALLBACK, callBack);
        } catch (QiniuException e) {
            // 请求失败时简单状态信息
            try {
                LogUtil.error(logger, e.response.toString() + " 响应的文本信息:" + e.response.bodyString());

            } catch (QiniuException e1) {
                LogUtil.error(logger, e1.toString());
            }
        }
    }

    @Override
    public void transFormMedia(TransFormModule transFrom) {
        String bucketName = genBucketName(FileBelong.PRODUCT);
        Auth auth = getAuth(bucketName);

        //新建一个OperationManager对象
        OperationManager operator = new OperationManager(auth);

        //设置要转码的空间和key，并且这个key在你空间中存在
        String key = transFrom.getSourceKey();

        String fops = transFrom.getPfop();

        //可以对转码后的文件使用saveas参数自定义命名，当然也可以不指定，文件会默认命名并保存在当前空间
        String urlbase64 = UrlSafeBase64.encodeToString(qiniuScope + ":" + transFrom.getTargetKey());
        fops += "|saveas/" + urlbase64;


        //设置pipeline参数
        StringMap params = new StringMap().putWhen("force", 1, true).putNotEmpty("pipeline", qiniuPipeline);//先不写callback .put("notifyURL", callBackUrl);

        try {
            String persistid = operator.pfop(qiniuScope, key, fops, params);
            System.out.println("persistid=" + persistid + "sourceKey=" + transFrom.getSourceKey() + "targetKey=" + transFrom.getTargetKey());

        } catch (QiniuException e) {
            // 请求失败时简单状态信息
            try {
                LogUtil.error(logger, e.response.toString() + " 响应的文本信息:" + e.response.bodyString());

            } catch (QiniuException e1) {
                LogUtil.error(logger, e1.toString());
            }
        }
    }


    @Override
    public QiniuCallBack callBackOption(QiniuPersistentModule persistentModule) {
        //根據id進行鎖
        synchronized (persistentModule.getId().intern()) {
            //根据带过来的id，获取到缓存
            String key_persistentId = CacheConstants.QINIU_CALLBACK;
            List<QiniuCallBack> callBacks = jedisUtil.lrangeAllObj(key_persistentId, QiniuCallBack.class);
            QiniuCallBack callBack = null;

            for (QiniuCallBack callBack1 : callBacks) {
                if (callBack1.getId().equals(persistentModule.getId())) {
                    callBack = callBack1;
                    continue;
                }
            }
            if (callBack == null) {
                LogUtil.info(logger, "在緩存裏面沒有查詢到對應的callBack對象！！！");
                return null;
            }

            if (!callBack.getIsSaved()) {//保存帖子之前的执行
                LogUtil.info(logger, "七牛隊列Id為" + callBack.getId() + "的，先執行的--回調--操作。");
                //先刪除
                jedisUtil.lrem(CacheConstants.QINIU_CALLBACK, callBack);

                callBack.setIsCallBack(true);
                //再更新
                jedisUtil.lpush(CacheConstants.QINIU_CALLBACK, callBack);

            }
            return callBack;
        }

    }

    private byte[] InputStreamToByte(InputStream is) throws IOException {
        ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int ch;
        /**
         *
         * */
        while ((ch = is.read(buffer)) != -1) {
            bytestream.write(buffer, 0, ch);
        }
        byte data[] = bytestream.toByteArray();
        bytestream.close();
        return data;
    }

    public UpLoadFileResult uploadFile(UploadRequest request) throws Exception {

        UpLoadFileResult fileResult = new UpLoadFileResult();

        InputStream in = request.getInputStream();

        if (in==null && SysStringUtils.isNotEmpty(request.getFetchUrl())) {
            Image image = this.uploadImgWithUrl(request.getFetchUrl());
            fileResult.setImage(image);

            return fileResult;
        }

        String bucketName = genBucketName(request.getBelong());
        String upToken = genUpToken(bucketName);
        UploadManager uploadManager = new UploadManager();

        Response res = uploadManager.put(InputStreamToByte(in), null, upToken);
        String resultBody = res.bodyString();
        if (SysStringUtils.isNotEmpty(resultBody)) {
            UpLoadFileVO file = new UpLoadFileVO(resultBody);

            if (file != null) {
                file.setKey(qiniuKeyToLocalKey(file.getKey(), bucketName));
                fileResult.setFile(file);
            }
        }

        return fileResult;
    }

    /**
     * 七牛返回的文件key转为本地保存到数据中的key
     */
    @Override
    public String qiniuKeyToLocalKey(String qiniuKey, String bucketName) {

        //加这一步操作，是因为 客户端会穿已经添加前缀的key
        if (!qiniuKey.startsWith(ResourceFacade.FILE_STORE_KEY_V2 + bucketName + SPLIT_SYMBOL)) {
            return ResourceFacade.FILE_STORE_KEY_V2 + bucketName + SPLIT_SYMBOL + qiniuKey;
        }
        return qiniuKey;

    }

    @Override
    public String genUpTokenForClient(String bucketName) {
       /* QiniuBean bean = findQiniuBeanByBucketName(bucketName);
//		Config.ACCESS_KEY = bean.accessKey;
//		Config.SECRET_KEY = bean.secretKey;
        Mac mac = new Mac(bean.accessKey, bean.secretKey);

        PutPolicy putPolicy = new PutPolicy(bucketName);
        String uptoken = putPolicy.token(mac);
        return uptoken;*/

        return null;
    }


    public static void main(String[] args) {


        // String key = genQiniuFileKey1("http://image1.xunbaozl.com/e01ec78d-8f0f-4325-a2d5-9182b7552aff?imageInfo");
        //System.out.println(key);

        //image1.xunbaozl.com/e01ec78d-8f0f-4325-a2d5-9182b7552aff?
        // java.net.URL a=new java.net.URL("image1.xunbaozl.com/e01ec78d-8f0f-4325-a2d5-9182b7552aff");

    }

    @Override
    public Image uploadImgWithUrl(String imgUrl) {
        LogUtil.info(logger, "通过图片url更新图片");

        if (SysStringUtils.isNullOrEmpty(imgUrl))
            return null;

        String bucketName = genBucketName(FileBelong.PRODUCT);
        String key = UUID.randomUUID().toString();
        String imageKey = qiniuKeyToLocalKey(key, bucketName);

        Auth auth = getAuth(bucketName);
        BucketManager bucketManager = new BucketManager(auth);

        try {
            DefaultPutRet defaultPutRet = bucketManager.fetch(imgUrl, bucketName, key);
            System.out.println(defaultPutRet);

            String bucketUrl = genBucketSiteHost(FileBelong.PRODUCT);
            if (!bucketUrl.endsWith("/")) {
                bucketUrl += "/";
            }
            bucketUrl += key;

            return genQiniuImageInfo(bucketUrl);
        } catch (QiniuException e) {
            LogUtil.error(logger, "转储图片失败！" + e);
        } catch (Exception e) {
            LogUtil.error(logger, "转储图片失败！" + e);
        }
        return null;
    }

    @Override
    public Image genQiniuImageInfo(String qiniuUrl) {
        LogUtil.info(logger, "获取七牛服务器上的图片信息. qiniuUrl:" + qiniuUrl);
        Image image = null;
        if (SysStringUtils.isNotEmpty(qiniuUrl)) {
            String imageInfo = "?imageInfo";
            if (!qiniuUrl.endsWith(imageInfo)) {
                qiniuUrl = qiniuUrl + imageInfo;
            }
            try {
                String response = HttpUtil.getRequest(qiniuUrl);
                LogUtil.info(logger, "response:" + response);
                QiniuImageInfo info = JSON.parseObject(response, QiniuImageInfo.class);
                LogUtil.info(logger, "QiniuImageInfo:" + info.toString());

                String qiniuKey = genQiniuKeyWithUrl(qiniuUrl);
                LogUtil.info(logger, "qiniuKey:" + qiniuKey);
                String localKey = qiniuKeyToLocalKey(qiniuKey, genBucketName(FileBelong.PRODUCT));
                LogUtil.info(logger, "localKey:" + localKey);
                if (info != null)
                    image = createImageByLocalKeyAndInfo(localKey, info);
            } catch (Exception e) {
                LogUtil.error(logger, "获取七牛服务器上的图片信息失败." + e);
            }
        }
        return image;
    }

    private Image createImageByLocalKeyAndInfo(String localKey, QiniuImageInfo info) {
        Image image = null;
        if (SysStringUtils.isNotEmpty(localKey)) {
            image = new Image();
            image.setBelong(FileBelong.PRODUCT);
            image.setId(null);
            image.setCreatedAt(new Date());
            image.setCropX(0d);
            image.setCropY(0d);
            image.setKey(localKey);

            ResourceFacade rsfacade=SpringContextUtil.getBean(ResourceFacade.class);

            if(rsfacade!=null)
                image.setImgUrl(rsfacade.resolveUrl(localKey, false));

            if (info != null) {
                image.setCropWidth((double) info.getWidth());
                image.setCropHeight((double) info.getHeight());
                image.setHeight(info.getHeight());
                image.setWidth(info.getWidth());
                image.setSuffix("." + info.getFormat());
            }
        }

        return image;
    }

    private String genQiniuKeyWithUrl(String qiniuUrl) {

        URL url = null;
        try {
            url = new URL(qiniuUrl);
            qiniuUrl = url.getPath();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        String key = null;
        if (SysStringUtils.isNotEmpty(qiniuUrl)) {
            int start = qiniuUrl.indexOf('/') + 1;
            int end = qiniuUrl.length();
            if (end > start) {
                key = SysStringUtils.substring(qiniuUrl, start, qiniuUrl.length());
            }
        }
        return key;
    }
}
